unit uBaiduMapAPI;

interface

uses
  SysUtils, uDZBase64, uDZWinInetUtils, uGxtCity;

function CoordGoogle2Baidu(const GLng, GLat: AnsiString;
  out BLng, BLat: AnsiString): Boolean;

function CoordGPS2Baidu(const GLng, GLat: AnsiString;
  out BLng, BLat: AnsiString): Boolean;

procedure LngLatToMercator(Lng, Lat: Extended; out X, Y: Extended);

function GetLocation(const Lng, Lat: Extended; out Address,
  ProvinceName, CityName: WideString; pCityID: PInteger): Boolean;
  
implementation

const
  LLBAND: array [0..5] of Integer = (75, 60, 45, 30, 15, 0);
  LL2MC: array [0..5] of array [0..9] of Extended =
    ((-0.0015702102444, 111320.7020616939, 1704480524535203, -10338987376042340,
      26112667856603880,-35149669176653700,26595700718403920,-10725012454188240,
      1800819912950474,82.5),
      (0.0008277824516172526,111320.7020463578,647795574.6671607,-4082003173.641316,
      10774905663.51142,-15171875531.51559,12053065338.62167,-5124939663.577472,
      913311935.9512032,67.5),
      (0.00337398766765,111320.7020202162,4481351.045890365,-23393751.19931662,
      79682215.47186455,-115964993.2797253,97236711.15602145,-43661946.33752821,
      8477230.501135234,52.5),
      (0.00220636496208,111320.7020209128,51751.86112841131,3796837.749470245,
      992013.7397791013,-1221952.21711287,1340652.697009075,-620943.6990984312,
      144416.9293806241,37.5),
      (-0.0003441963504368392,111320.7020576856,278.2353980772752,2485758.690035394,
      6070.750963243378,54821.18345352118,9540.606633304236,-2710.55326746645,
      1405.483844121726,22.5),
      (-0.0003218135878613132,111320.7020701615, 0.00369383431289,823725.6402795718,
      0.46104986909093,2351.343141331292,1.58060784298199,8.77738589078284,
      0.37238884252424,7.45));

function GetLoop(cC, cB, T: Extended): Extended;
begin
  while cC > T do cC := cC - (T- cB);
  while cC < cB do cC := cC + (T-cB);
  Result := cC;
end;

function GetRange(cC, cB, T: Extended): Extended;
begin
  //if(cB!=null){
  if cC < cB then cC := cB;
  //}
  //if(T!=null){
  if cC > T then cC := T;
  //}
  Result := cC; 
end;

procedure Convertor(Lng, Lat: Extended; cD: Integer;
  out RLng, RLat: Extended);
var
  cB: Extended;
begin
  RLng := LL2MC[cD][0] + LL2MC[cD][1]*Abs(Lng);
  cB := Abs(Lat)/LL2MC[cD][9];
  RLat := LL2MC[cD][2] + LL2MC[cD][3]*cB + LL2MC[cD][4]*cB*cB + LL2MC[cD][5]*cB*cB*cB +
    LL2MC[cD][6]*cB*cB*cB*cB + LL2MC[cD][7]*cB*cB*cB*cB*cB +
    LL2MC[cD][8]*cB*cB*cB*cB*cB*cB;
  if Lng < 0 then RLng := -RLng;
  if Lat < 0 then RLat := -RLat;
end;

procedure LngLatToMercator(Lng, Lat: Extended; out X, Y: Extended);
var
  //cBLng,
  cBLat: Extended;
  cC, cDIndex: Integer;
begin
  //var cB,cD;
  Lng := GetLoop(Lng, -180, 180);
  Lat := GetRange(Lat, -74, 74);
  //cBLng := Lng;
  cBLat := Lat;
  cDIndex := -1;
  for cC := 0 to High(LLBAND) do
  begin
    if cBLat >= LLBAND[cC] then
    begin
      cDIndex := cC;
      Break;
    end;
  end;
  if cDIndex = - 1 then
  begin
    for cC := High(LLBAND) downto 0 do
    begin
      if cBLat <= -LLBAND[cC] then
      begin
        cDIndex := cC;
        Break;
      end;
    end;
  end;
  Convertor(Lng, Lat, cDIndex, X, Y);
end;

function JsonGetProperty(const Json, Name: AnsiString; out Value: AnsiString): Boolean;
var
  JsonLen, NamePos, VStart: Integer;
  Quoted: Boolean;
begin
  Result := False;
  NamePos := Pos('"' + Name + '"', Json);
  if NamePos <= 0 then Exit;
  Inc(NamePos, Length(Name) + 2);
  JsonLen := Length(Json);
  while (NamePos <= JsonLen) and (Json[NamePos] <> ':') do Inc(NamePos);
  if NamePos > JsonLen then Exit;
  Inc(NamePos);
  while (NamePos <= JsonLen) and (Json[NamePos] = #32) do Inc(NamePos);
  if NamePos > JsonLen then Exit;
  if Json[NamePos] = '"' then
  begin
    Quoted := True;
    Inc(NamePos);
    VStart :=  NamePos;
  end
  else if Json[NamePos] in ['[', '{', '('] then Exit
  else begin
    Quoted := False;
    VStart := NamePos;
    Inc(NamePos);
  end;

  if Quoted then
    while (NamePos <= JsonLen) and (Json[NamePos] <> '"') do Inc(NamePos)
  else
    while (NamePos <= JsonLen) and not (Json[NamePos] in [',', '}']) do Inc(NamePos);
  if NamePos > JsonLen then Exit;
  Value := Copy(Json, VStart, NamePos - VStart);
  Result := True;
end;

function BaiduCoordConvert(SrcID, DestID: Integer;
  const SrcLng, SrcLat: AnsiString;
  out DestLng, DestLat: AnsiString): Boolean;
var
  Url, Json, ErrorCode: AnsiString;
begin
  Result := False;
  Url := Format('http://api.map.baidu.com/ag/coord/convert?from=%d&to=%d&x=%s&y=%s',
    [SrcID, DestID, SrcLng, SrcLat]);
  try
    Json := HttpGet(Url);
    if not JsonGetProperty(Json, 'error', ErrorCode) or (ErrorCode <> '0') then Exit;
    if not JsonGetProperty(Json, 'x', DestLng) or
      not JsonGetProperty(Json, 'y', DestLat) then Exit;
    DestLng := Base64Decode(DestLng);
    DestLat := Base64Decode(DestLat);
    Result := True;
  except

  end;
end;

function CoordGoogle2Baidu(const GLng, GLat: AnsiString;
  out BLng, BLat: AnsiString): Boolean;
begin
  Result := BaiduCoordConvert(2, 4, GLng, GLat, BLng, BLat);
end;

function CoordGPS2Baidu(const GLng, GLat: AnsiString;
  out BLng, BLat: AnsiString): Boolean;
begin
  Result := BaiduCoordConvert(0, 4, GLng, GLat, BLng, BLat);
end;

function GetLocation(const Lng, Lat: Extended; out Address,
  ProvinceName, CityName: WideString; pCityID: PInteger): Boolean;
const
  PROVINCE_CHAR: WideChar = #30465;
  CITY_CHAR: WideChar = #24066;
var
  X, Y: Extended;
  Url, Json, Value: AnsiString;
  City: uGxtCity.TCity;

  procedure DeleteTitle(var src: WideString; tc: WideChar);
  begin
    if src = '' then Exit;
    if src[Length(src)] = tc then SetLength(src, Length(src) - 1);
  end;
begin
  Result := False;
  LngLatToMercator(Lng, Lat, X, Y);
  Url := Format('http://api.map.baidu.com/?qt=rgc&x=%.2f&y=%.2f', [X, Y]);
  with uGxtCity.AreaList do
  try
    Json := HttpGet(Url);
    if not JsonGetProperty(Json, 'address', Value) then Exit;
    Address := UTF8Decode(Value);
    if JsonGetProperty(Json, 'province', Value) then
    begin
      ProvinceName := UTF8Decode(Value);
      DeleteTitle(ProvinceName, PROVINCE_CHAR);
      ProvinceName := GetCnProvinceName(ProvinceName);
    end
    else ProvinceName := '';
    if JsonGetProperty(Json, 'city', Value) then
    begin
      CityName := UTF8Decode(Value);
      DeleteTitle(CityName, CITY_CHAR);
      CityName := GetCnCityName(CityName);
    end
    else CityName := '';
    if Assigned(pCityID) and (CityName <> '') then
    begin
      City := GetCityByName(CityName);
      pCityID^ := City.ID;
    end;
    Result := True;
  except

  end;
end;

end.
